/*********************************************************************************
 *      Copyright:  (C) 2019 Wu Yujun<540726307@qq.com>
 *                  All rights reserved.
 *
 *       Filename:  packet_pdu_sms.c
 *    Description:  This file test pdu_sms.c
 *                 
 *        Version:  1.0.0(2019年07月30日)
 *         Author:  Wu Yujun <540726307@qq.com>
 *      ChangeLog:  1, Release initial version on "2019年07月30日 10时55分04秒"
 *                 
 ********************************************************************************/
#include "packet_pdu_sms.h"


int packet_pdu(const char *center, const char *rec_phone, const char *content, char *out_str, int out_size)
{
    int     rv = -1 ;
    char    sms[512] ;
    char    unicode[512] ;


    if( center == NULL || rec_phone == NULL || content == NULL || out_str == NULL || out_size <= 0)
    {
        printf("Invail parameter in %s\n", __FUNCTION__) ;
        return -1 ;
    }
    
    rv = string2unicode(content, unicode, sizeof(unicode)) ;
    if(rv < 0)
    {
        printf("string2unicode() failed\n") ;
        return -2 ;
    }

    memset(sms, 0, sizeof(sms)) ;
    rv = packet_pdu_sms(center, rec_phone, unicode, sms, sizeof(sms)) ;
    if(rv < 0)
    {
        printf("format error\n") ;
        return -3 ;
    }
    
    if( out_size < strlen(sms) )
    {
        printf("str size too short\n") ;
        return -4 ;
    }

    strncpy(out_str, sms, strlen(sms)) ;
    return rv ;
}

/*************************************************************
 * Describe:chinese string to unicode,need zh_CN.utf8 locale
 *
 * Return:
 *      sucess return 0, fail return negetive
 ***********************************************************/
int string2unicode(const char*str, char *out, int out_size)
{
    wchar_t         chinese_str[512];
    int             i;
    int             rv = 0 ;
    int             bytes = 0 ;


    if( str == NULL || out == NULL || out_size <= 0)
    {
        printf("Invail input in %s\n", __FUNCTION__) ;
        return -1 ;
    }

    setlocale(LC_ALL, "zh_CN.utf8");
    wmemset(chinese_str,0,512) ;
    rv = mbstowcs(chinese_str,str,512) ;
    if(rv <=0 ) 
    {
        printf("mbstowcs fail\n") ;
        return -2 ;
    }
    /*   swprintf(chinese_str, LEN, L"%S",L"你好") ;*/
    /*   printf("mbstowcs return value=%d,Uniocde: \n",rv); */
    for (i = 0; i < wcslen(chinese_str); i++)
    {
        snprintf(&out[bytes], out_size-bytes,"%x",(unsigned int)chinese_str[i]);
        if( (unsigned int)chinese_str[i] >= 0x4E00 && (unsigned int)chinese_str[i] <= 0x9FBB)
        {
            snprintf(&out[bytes], out_size-bytes,"%x",(unsigned int)chinese_str[i]);
        }
        else
        {
            snprintf(&out[bytes], out_size-bytes,"00%x",(unsigned int)chinese_str[i]);
        }
        bytes = bytes + 4 ;
        if(bytes > out_size)
        {
            printf("output string size too small\n") ;
            return -3 ;
        }
    }
#if 1
    printf("%s\n", out) ;
    printf("wchar_t size:%d\n",(int)sizeof(wchar_t)) ;
#endif

    return 0 ;
}


/* ***********************************************************************************************  
 *  Describe:format receiver sms phone number for send pdu sms
 *  
 *  Input parameter: 
 *               const char *center_num is string of center sms phone number
 *               const char *rec_num is string of receiver sms phone number
 *               const char *mess is message content by Unicode ,mess content must be Unicode!!!
 *  Output parameter:
 *               char *out_str is after packet pdu sms 
 *  Return:
 *               OK return send length for AT+CMGS=${Send Length}; Fail return negative
 **************************************************************************************************/
int packet_pdu_sms(const char *center_num, const char *rec_num, const char *mess, char *out_str, int out_size)
{
    int     rv = -1 ;
    char    center[64] ;
    char    receiver[64] ;
    char    sms_mess[512] ;
    int     sms_length = 0;
    int     cmgs_len = 0 ;


    if(!center_num || !rec_num || !mess || !out_str || out_size <= 0)
    {
        printf("Invail paremeter in %s\n", __FUNCTION__) ;
        return -1 ;
    }
    memset(center, 0, sizeof(center)) ;
    rv = format_center_num(center_num, center, sizeof(center)) ;
    if(rv < 0)
    {
        printf("format center sms phone number error\n") ;
        return -2 ;
    }

    memset(receiver, 0, sizeof(receiver)) ;
    rv = format_receive_num(rec_num, receiver, sizeof(receiver)) ;
    if(rv < 0)
    {
        printf("format receiver phone number error\n") ;
        return -3 ;
    }

    sms_length = strlen(mess) ;
    sms_length = sms_length/2 ;
    memset(sms_mess, 0, sizeof(sms_mess)) ;
    if(sms_length<16)
    {
        snprintf(sms_mess, sizeof(sms_mess),"0%x%s",sms_length,mess) ;
    }
    else{
        snprintf(sms_mess, sizeof(sms_mess),"%x%s",sms_length,mess) ;
    }
    snprintf(out_str, out_size,"%s%s%s", center,receiver,sms_mess) ;
    cmgs_len = strlen(receiver)+strlen(sms_mess) ;
    cmgs_len = cmgs_len/2;

    return cmgs_len ;
}


/* ***********************************************************************
 *  *  Describe:format receiver sms phone number for send pdu sms
 *   *
 *    *  Input parameter: 
 *     *              const char *rec_num is string of receiver sms phone number
 *      *  Output parameter:
 *       *              char *out_str is after format receiver sms phone number output 
 *        *  Return:
 *         *          OK return 0; Fail return negative
 *          ***********************************************************************/
int format_receive_num(const char *rec_num,char *out_str, int out_size) 
{
    const char      *ptr = NULL ;
    char            temp_str[64] ;
    int             rv = -1 ;
    int             length = 0 ;

    if( !rec_num || !out_str || out_size <= 0)
    {
        printf("Invail parameter in %s\n", __FUNCTION__) ;
        return -1 ;
    }
    memset(temp_str, 0, sizeof(temp_str)) ;
    rv = format_phone_num(rec_num, temp_str, sizeof(temp_str)) ;
    if(rv < 0)
    {
        printf("format_phone_num %s fail in %s\n",rec_num, __FUNCTION__) ;
        return -2 ;
    }

    ptr = rec_num ;
    if(ptr[0] == '+')
    {
        ptr = ptr+1 ;
        if( !(*ptr) )
        {
            printf("invail receive phone number:%s\n",rec_num) ;
            return -3 ;
        }
    }
    length = strlen(ptr) ; //Length of the receive phone number
    /*  "1100" and "000800" are fixed prefixes and suffixes of the receiver phone number
     *       *  if the number of the receiver is mobile phone, it will add "91", if it is PHS add "81"*/
    if(length < 16) 
    {
        snprintf(out_str, out_size, "11000%x91%s000800", length, temp_str) ;
    }
    else
    {
        snprintf(out_str, out_size,"1100%x91%s000800", length, temp_str);
    }
    return 0 ;
}


/* ***********************************************************************
 *  *  Describe:format center sms phone number for send pdu sms
 *   *
 *    *  Input parameter: 
 *     *              const char *center_num is string of center sms phone number
 *      *  Output parameter:
 *       *              char *out_str is after format center sms phone number output 
 *        *  Return:
 *         *          OK return 0; Fail return negative
 *          ***********************************************************************/
int format_center_num(const char *center_num,char *out_str, int out_size) 
{
    char            temp_str[64] ;
    int             rv = -1 ;
    int             length = 0 ;

    if( !center_num || !out_str || out_size <= 0)
    {
        printf("Invail parameter in %s\n", __FUNCTION__) ;
        return -1 ;
    }

    memset(temp_str, 0, sizeof(temp_str)) ;
    rv = format_phone_num(center_num, temp_str, sizeof(temp_str)) ;
    if(rv < 0)
    {
        printf("format_phone_num %s fail in %s\n",center_num, __FUNCTION__) ;
        return -2 ;
    }

    length = strlen(temp_str) ;
    length = length + 2 ; //Add the number 91 logo of Internationalization in the head 
    length = length/2 ;//Length divided by 2(hex values)
    if(length < 16)
    {
        snprintf(out_str, out_size, "0%x91%s", length, temp_str) ;
    }
    else
    {
        snprintf(out_str, out_size,"%x91%s", length, temp_str);
    }

    return 0 ;
}


/* ***********************************************************************************
 *  *  Describe:fomatt phone_number for send pdu sms , Delete '+', 
 *   *      if string is odd add 'F', and swap the odd position and even position 
 *    * 
 *     *  Input parameter: 
 *      *                  char *phone_num,phone_number string you want to format
 *       *
 *        *  Output parameter:
 *         *                  char *out_str, After fomat phone number string output to out_str
 *          *  Return :
 *           *          Successful retrun 0; Fail return negative
 *            ***********************************************************************************/
int format_phone_num(const char *phone_num, char *out_str, int out_size)
{
    const char      *ptr = NULL ;
    int             len = 0 ;
    char            temp_out[64] ;
    int             rv ;

    if(!phone_num || !out_str || out_size<=0 )
    {
        printf("Invail parameter in %s\n",__FUNCTION__) ;
        return -1 ;
    }
    ptr = phone_num ;
    if(ptr[0] == '+') //if have '+' Delete '+'
    {
        ptr = ptr+1 ;
        if( !(*ptr) )//if ptr point end of string "/0"
        {
            printf("Invail phone number\n") ;
            return -2 ;
        }
    }
    memset(temp_out, 0, sizeof(temp_out)) ;
    snprintf(temp_out, sizeof(temp_out), "%s", ptr) ;
    len = strlen(ptr) ;
    if( (len % 2) != 0) //if phone number string is odd, add 'F' in the last
    {
        strncat(temp_out, "F", sizeof(temp_out)) ;
    }
    rv = swap_odd_even(temp_out, strlen(temp_out), out_str, out_size) ;
    if(rv < 0)
    {
        printf("swap phone number strings the odd position and even position of the neighbour failed\n") ;
        return -3 ;
    }

    return 0 ;
}


/* ****************************************************************************
 *  *  Describe:swap strings the odd position and even position of the neighbour
 *   *  
 *    *  Input parameter:
 *     *                  const char *str, the string you want to swap
 *      *                  int str_len, strlen of the string , it must be even
 *       *                  int out_str, char *str_out size, output string size
 *        *  Output parameter:
 *         *                  char *str, the string after swap output to char *str_out
 *          *
 *           *  Return:Successful return 0, Fail return negative
 *            *****************************************************************************/
int swap_odd_even(const char *str,int str_len, char *str_out, int out_size)
{
    int         i ;
    char        temp ;

    if( !str || str_len <= 0 || !str_out|| out_size < str_len)
    {
        printf("Invail input parameter in %s\n",__FUNCTION__) ;
        return -1 ;
    }
    if( str_len % 2 )//The string is odd
    {
        printf("Please input a size of string is even\n") ;
        return -2 ;
    }
    snprintf(str_out, out_size, "%s", str) ;
    for( i = 0; i < str_len-1; i = i+2 )
    {
        temp = str_out[i] ;
        str_out[i] = str_out[i+1] ;
        str_out[i+1] = temp ;
    }
    return 0 ;
}
